package com.lizi.apidoc.builder;

import com.lizi.apidoc.constants.AnnotationKeyName;
import com.lizi.apidoc.constants.AnnotationName;
import com.lizi.apidoc.constants.DocGlobal;
import com.lizi.apidoc.constants.DocTags;
import com.lizi.apidoc.model.ApiObjectProperty;
import com.lizi.apidoc.utils.*;
import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 类属性获取器
 *
 * @author kingman zhangjw@3vjia.com
 * @since 2020-05-07 11:50
 */
public class ClassPropertyGetter {

    public static List<ApiObjectProperty> getProperties(JavaClass javaClass) {
        String classFullName = javaClass.getFullyQualifiedName();

        List<JavaField> fields = JavaClassUtil.getFields(javaClass, 0);
        if (ArraysUtil.isNullOrEmpty(fields)) {
            return null;
        }
        List<ApiObjectProperty> apiObjectProperties = new ArrayList<>();
        for (JavaField field : fields) {
            ApiObjectProperty apiObjectProperty = javaFieldConvertToApiObjectProperty(field);
            if (apiObjectProperty == null) {
                continue;
            }
            apiObjectProperties.add(apiObjectProperty);
        }
        return apiObjectProperties;
    }

    /**
     * 把 javaField 转为 ApiObjectProperty 对象
     * @return
     */
    private static ApiObjectProperty javaFieldConvertToApiObjectProperty(JavaField field)
    {
        String fieldName = field.getName();
        String fullyQualifiedName = field.getType().getFullyQualifiedName();
        if (field.isStatic() || "this$0".equals(fieldName) ||
                JavaClassValidateUtil.isIgnoreFieldTypes(fullyQualifiedName)) {
            return null;
        }
        String typeSimpleName = field.getType().getSimpleName();
        String fieldGicName = field.getType().getGenericCanonicalName();
        String genericValue = field.getType().getGenericValue();
        String comment = field.getComment();
        boolean strRequired = false;
        List<JavaAnnotation> javaAnnotations = field.getAnnotations();
        Map<String, String> tagsMap = DocUtil.getFieldTagsValue(field);
        String since = DocGlobal.DEFAULT_VERSION;//since tag value
        if(tagsMap.containsKey(DocTags.SINCE)){
            since = tagsMap.get(DocTags.SINCE);
        }

        for (JavaAnnotation annotation : javaAnnotations) {
            String annotationName = annotation.getType().getSimpleName();

            if (AnnotationName.SHORT_JSON_IGNORE.equals(annotationName)) {
                //JsonIngore 忽略
                return null;
            }
            else if(AnnotationName.SHORT_JSON_FIELD.equals(annotationName)){
                if (null != annotation.getProperty(AnnotationKeyName.SERIALIZE_PROP)) {
                    //不需要序列化
                    if (Boolean.FALSE.toString().equals(annotation.getProperty(AnnotationKeyName.SERIALIZE_PROP).toString())) {
                        return null;
                    }
                } else if (null != annotation.getProperty(AnnotationKeyName.NAME)) {
                    fieldName = StringUtil.removeQuotes(annotation.getProperty(AnnotationKeyName.NAME).toString());
                }
            }
            else if (AnnotationName.SHORT_JSON_PROPERTY.equals(annotationName)) {
                if (null != annotation.getProperty(AnnotationKeyName.VALUE)) {
                    fieldName = StringUtil.removeQuotes(annotation.getProperty(AnnotationKeyName.VALUE).toString());
                }
            }
            else if (AnnotationName.NULL.equals(annotationName)) {
                strRequired = false;
            }
            else if (JavaClassValidateUtil.isJSR303Required(annotationName)) {
                strRequired = true;
            }

        }

        String formatType = DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase());
        if(StringUtil.isNullOrEmpty(comment)){
            comment = DocGlobal.NO_COMMENTS_FOUND;
        }
        String ref = fullyQualifiedName;
        if (!JavaClassValidateUtil.isPrimitive(typeSimpleName.toLowerCase()))
        {
            typeSimpleName="object";
            ref = (String.format("#/components/schemas/%s",fullyQualifiedName));
        }

        ApiObjectProperty apiObjectProperty = new ApiObjectProperty();
        apiObjectProperty.setDescription(comment);
        apiObjectProperty.setFormat(formatType);
        apiObjectProperty.setFieldFullClassName(fullyQualifiedName);
        apiObjectProperty.setName(fieldName);
        apiObjectProperty.setRequired(strRequired);
        apiObjectProperty.setType(typeSimpleName.toLowerCase());
        apiObjectProperty.setRef(ref);
        apiObjectProperty.setVersion(since);
        if("array".equals(formatType)){
            ApiObjectProperty items = new ApiObjectProperty();
            String genericType = DocClassUtil.getSimpleGicName(genericValue)[0];
            if (!JavaClassValidateUtil.isPrimitive(genericType)) {
                genericType = "object";
                String fullGenericType = DocClassUtil.getSimpleGicName(fieldGicName)[0];
                items.setFieldFullClassName(fullGenericType);
                items.setRef(String.format("#/components/schemas/%s",fullGenericType));
            }
            items.setType(genericType);
            items.setNullable(true);
            apiObjectProperty.setItems(items);
            apiObjectProperty.setType(formatType);
        }
        return apiObjectProperty;

    }
}
